package com.region.loadbalancer.policy;

import com.region.loadbalancer.group.Server;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Response Time Weighting Policy
 *
 * @author liujieyu
 * @date 2023/5/27 16:12
 * @desciption
 */
public class ResponseTimePolicy extends WeightPolicy {

    @Override
    protected void setAllWeight(List<Server> servers) throws UnsupportedOperationException {
        if (realWeight == null) {
            realWeight = new CopyOnWriteArrayList<>();
            for (int i = 0; i < servers.size(); i++) {
                realWeight.add(i, 1);
            }
        } else {
            Server minServer = getMinAvg(servers);
            for (int i = 0; i < servers.size(); i++) {
                if (minServer == servers.get(i)) {
                    realWeight.set(i, 1);
                } else {
                    double avgTime = servers.get(i).getAvgTime();
                    if (avgTime == 0.0f || minServer.getAvgTime() == 0.0f) {
                        realWeight.set(i, 1);
                    } else {
                        double multipleTime = minServer.getAvgTime() / avgTime;
                        while (true) {
                            if (multipleTime < 1) {
                                expandWeight(realWeight);
                                multipleTime = 10.0 * multipleTime;
                            } else {
                                break;
                            }
                        }
                        realWeight.set(i, (int) multipleTime);
                    }
                }
            }
        }
    }

    private void expandWeight(List<Integer> weight) {
        for (int i = 0; i < weight.size(); i++) {
            weight.set(i, weight.get(i) * 10);
        }
    }

    @Override
    protected int getWeightByIndex(int index) throws UnsupportedOperationException {
        return realWeight.get(index);
    }

    @Override
    public BalancerPolicy deepClone() {
        return new ResponseTimePolicy();
    }

    private Server getMinAvg(List<Server> servers) {
        int index = 0;
        double minAvg = 0;
        for (int i = 0; i < servers.size(); i++) {
            if (servers.get(i).getAvgTime() < minAvg) {
                minAvg = servers.get(i).getAvgTime();
                index = i;
            }
        }
        return servers.get(index);
    }
}
